/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Global Trust Authority is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

use crate::resource_facade::endorsement::Endorsement;
use actix_web::{web, HttpRequest, HttpResponse};
use endorserment::entities::cert_request::{AddCertRequest, DeleteRequest, QueryInfo, UpdateCertRequest};
use endorserment::services::cert_service::CertService;
use sea_orm::DatabaseConnection;
use serde_json::{json, Value};
use std::sync::{Arc, OnceLock};
use common_log::{error, info};

pub struct EndorsementProxy;

static ENDORSEMENT_PROXY_INSTANCE: OnceLock<Arc<EndorsementProxy>> = OnceLock::new();

impl EndorsementProxy {
    pub(crate) fn new() -> Self {
        Self
    }

    pub fn instance() -> &'static Arc<EndorsementProxy> {
        ENDORSEMENT_PROXY_INSTANCE.get_or_init(|| Arc::new(EndorsementProxy::new()))
    }

    fn validate_user_id(&self, req: &HttpRequest) -> Option<HttpResponse> {
        if req.headers().get("User-Id").is_none() {
            return Some(HttpResponse::BadRequest().json(json!({
                "message": "Missing or Invalid User-Id header",
            })));
        }
        None
    }
}

impl Endorsement for EndorsementProxy {
    async fn get_certs(
        &self,
        db: web::Data<Arc<DatabaseConnection>>,
        query: web::Query<Value>,
        req: HttpRequest,
    ) -> HttpResponse {
        info!("Received request to get certs");
        if let Some(err) = self.validate_user_id(&req) {
            return err;
        }
        
        let query: QueryInfo = match serde_json::from_str(&query.to_string()) {
            Ok(query) => query,
            Err(err) => return HttpResponse::BadRequest().json(json!({
                "message": format!("Invalid query format: {}", err)
            })),
        };
        
        let ids: Option<Vec<String>> =
            if let Some(ids) = query.ids { Some(ids.split(',').map(String::from).collect()) } else { None };
        
        let user_id = req.headers().get("User-Id").unwrap().to_str().unwrap();
        
        match CertService::get_all_certs(db, &ids, &query.cert_type, user_id).await {
            Ok(res) => res,
            Err(err) => {
                HttpResponse::build(err.status_code())
                    .json(json!({ "message": err.message() }))
            }
        }
    }

    async fn add_cert(
        &self,
        db: web::Data<Arc<DatabaseConnection>>,
        add_cert: web::Json<Value>,
        req: HttpRequest,
    ) -> HttpResponse {
        info!("Received request to add cert");
        if let Some(err) = self.validate_user_id(&req) {
            return err;
        }
        
        let add_cert: AddCertRequest = match serde_json::from_str(&add_cert.to_string()) {
            Ok(add_cert) => add_cert,
            Err(err) => return HttpResponse::BadRequest().json(json!({
                "message": format!("Invalid request format: {}", err)
            })),
        };
        
        let user_id = req.headers().get("User-Id").unwrap().to_str().unwrap();
        
        match CertService::add_cert(db, add_cert, user_id).await {
            Ok(res) => res,
            Err(err) => {
                HttpResponse::build(err.status_code())
                    .json(json!({ "message": err.message() }))
            }
        }
    }

    async fn delete_cert(
        &self,
        db: web::Data<Arc<DatabaseConnection>>,
        delete_request: web::Json<Value>,
        req: HttpRequest,
    ) -> HttpResponse {
        info!("Received request to delete cert");
        if let Some(err) = self.validate_user_id(&req) {
            return err;
        }
        
        let delete_request: DeleteRequest = match serde_json::from_str(&delete_request.to_string()) {
            Ok(delete_request) => delete_request,
            Err(err) => return HttpResponse::BadRequest().json(json!({
                "message": format!("Invalid request format: {}", err)
            })),
        };
        
        let user_id = req.headers().get("User-Id").unwrap().to_str().unwrap();
        
        match CertService::delete_certs(db, delete_request, user_id).await {
            Ok(res) => res,
            Err(err) => {
                HttpResponse::build(err.status_code())
                    .json(json!({ "message": err.message() }))
            }
        }
    }

    async fn update_cert(
        &self,
        db: web::Data<Arc<DatabaseConnection>>,
        update_cert: web::Json<Value>,
        req: HttpRequest,
    ) -> HttpResponse {
        info!("Received request to update cert");
        if let Some(err) = self.validate_user_id(&req) {
            return err;
        }
        
        if update_cert.get("content").is_some() {
            error!("When updating the certificate, it is not supported to pass in the content field");
            return HttpResponse::BadRequest().json(json!({
                "message": "When updating the certificate, it is not supported to pass in the content field"
            }));
        }
        
        let update_cert: UpdateCertRequest = match serde_json::from_str(&update_cert.to_string()) {
            Ok(update_cert) => update_cert,
            Err(err) => return HttpResponse::BadRequest().json(json!({
                "message": format!("Invalid request format: {}", err)
            })),
        };
        
        let user_id = req.headers().get("User-Id").unwrap().to_str().unwrap();
        
        match CertService::update_cert(db, update_cert, user_id.to_string()).await {
            Ok(res) => res,
            Err(err) => {
                HttpResponse::build(err.status_code())
                    .json(json!({ "message": err.message() }))
            }
        }
    }
}
